home *** CD-ROM | disk | FTP | other *** search
/ PC Advisor 2010 April / PCA177.iso / ESSENTIALS / Firefox Setup.exe / nonlocalized / chrome / browser.jar / content / browser / utilityOverlay.js < prev    next >
Encoding:
JavaScript  |  2009-07-15  |  21.2 KB  |  644 lines

  1. //@line 39 "e:\builds\moz2_slave\win32_build\build\browser\base\content\utilityOverlay.js"
  2.  
  3. /**
  4.  * Communicator Shared Utility Library
  5.  * for shared application glue for the Communicator suite of applications
  6.  **/
  7.  
  8. var TAB_DROP_TYPE = "application/x-moz-tabbrowser-tab";
  9.  
  10. var gBidiUI = false;
  11.  
  12. function getBrowserURL()
  13. {
  14.   return "chrome://browser/content/browser.xul";
  15. }
  16.  
  17. function goToggleToolbar( id, elementID )
  18. {
  19.   var toolbar = document.getElementById(id);
  20.   var element = document.getElementById(elementID);
  21.   if (toolbar)
  22.   {
  23.     var isHidden = toolbar.hidden;
  24.     toolbar.hidden = !isHidden;
  25.     document.persist(id, 'hidden');
  26.     if (element) {
  27.       element.setAttribute("checked", isHidden ? "true" : "false");
  28.       document.persist(elementID, 'checked');
  29.     }
  30.   }
  31. }
  32.  
  33. function getTopWin()
  34. {
  35.   var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1']
  36.                                 .getService(Components.interfaces.nsIWindowMediator);
  37.   return windowManager.getMostRecentWindow("navigator:browser");
  38. }
  39.  
  40. function openTopWin( url )
  41. {
  42.   openUILink(url, {})
  43. }
  44.  
  45. function getBoolPref ( prefname, def )
  46. {
  47.   try { 
  48.     var pref = Components.classes["@mozilla.org/preferences-service;1"]
  49.                        .getService(Components.interfaces.nsIPrefBranch);
  50.     return pref.getBoolPref(prefname);
  51.   }
  52.   catch(er) {
  53.     return def;
  54.   }
  55. }
  56.  
  57. // Change focus for this browser window to |aElement|, without focusing the
  58. // window itself.
  59. function focusElement(aElement) {
  60.   // This is a redo of the fix for jag bug 91884
  61.   var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
  62.                      .getService(Components.interfaces.nsIWindowWatcher);
  63.   if (window == ww.activeWindow)
  64.     aElement.focus();
  65.   else {
  66.     // set the element in command dispatcher so focus will restore properly
  67.     // when the window does become active
  68.     var cmdDispatcher = document.commandDispatcher;
  69.     if (aElement instanceof Window) {
  70.       cmdDispatcher.focusedWindow = aElement;
  71.       cmdDispatcher.focusedElement = null;
  72.     }
  73.     else if (aElement instanceof Element) {
  74.       cmdDispatcher.focusedWindow = aElement.ownerDocument.defaultView;
  75.       cmdDispatcher.focusedElement = aElement;
  76.     }
  77.   }
  78. }
  79.  
  80. // openUILink handles clicks on UI elements that cause URLs to load.
  81. function openUILink( url, e, ignoreButton, ignoreAlt, allowKeywordFixup, postData, referrerUrl )
  82. {
  83.   var where = whereToOpenLink(e, ignoreButton, ignoreAlt);
  84.   openUILinkIn(url, where, allowKeywordFixup, postData, referrerUrl);
  85. }
  86.  
  87.  
  88. /* whereToOpenLink() looks at an event to decide where to open a link.
  89.  *
  90.  * The event may be a mouse event (click, double-click, middle-click) or keypress event (enter).
  91.  *
  92.  * On Windows, the modifiers are:
  93.  * Ctrl        new tab, selected
  94.  * Shift       new window
  95.  * Ctrl+Shift  new tab, in background
  96.  * Alt         save
  97.  *
  98.  * You can swap Ctrl and Ctrl+shift by toggling the hidden pref
  99.  * browser.tabs.loadBookmarksInBackground (not browser.tabs.loadInBackground, which
  100.  * is for content area links).
  101.  *
  102.  * Middle-clicking is the same as Ctrl+clicking (it opens a new tab) and it is
  103.  * subject to the shift modifier and pref in the same way.
  104.  *
  105.  * Exceptions: 
  106.  * - Alt is ignored for menu items selected using the keyboard so you don't accidentally save stuff.  
  107.  *    (Currently, the Alt isn't sent here at all for menu items, but that will change in bug 126189.)
  108.  * - Alt is hard to use in context menus, because pressing Alt closes the menu.
  109.  * - Alt can't be used on the bookmarks toolbar because Alt is used for "treat this as something draggable".
  110.  * - The button is ignored for the middle-click-paste-URL feature, since it's always a middle-click.
  111.  */
  112. function whereToOpenLink( e, ignoreButton, ignoreAlt )
  113. {
  114.   // This method must treat a null event like a left click without modifier keys (i.e.
  115.   // e = { shiftKey:false, ctrlKey:false, metaKey:false, altKey:false, button:0 })
  116.   // for compatibility purposes.
  117.   if (!e)
  118.     return "current";
  119.  
  120.   var shift = e.shiftKey;
  121.   var ctrl =  e.ctrlKey;
  122.   var meta =  e.metaKey;
  123.   var alt  =  e.altKey && !ignoreAlt;
  124.  
  125.   // ignoreButton allows "middle-click paste" to use function without always opening in a new window.
  126.   var middle = !ignoreButton && e.button == 1;
  127.   var middleUsesTabs = getBoolPref("browser.tabs.opentabfor.middleclick", true);
  128.  
  129.   // Don't do anything special with right-mouse clicks.  They're probably clicks on context menu items.
  130.  
  131. //@line 171 "e:\builds\moz2_slave\win32_build\build\browser\base\content\utilityOverlay.js"
  132.   if (ctrl || (middle && middleUsesTabs)) {
  133. //@line 173 "e:\builds\moz2_slave\win32_build\build\browser\base\content\utilityOverlay.js"
  134.     if (shift)
  135.       return "tabshifted";
  136.     else
  137.       return "tab";
  138.   }
  139.   else if (alt) {
  140.     return "save";
  141.   }
  142.   else if (shift || (middle && !middleUsesTabs)) {
  143.     return "window";
  144.   }
  145.   else {
  146.     return "current";
  147.   }
  148. }
  149.  
  150. /* openUILinkIn opens a URL in a place specified by the parameter |where|.
  151.  *
  152.  * |where| can be:
  153.  *  "current"     current tab            (if there aren't any browser windows, then in a new window instead)
  154.  *  "tab"         new tab                (if there aren't any browser windows, then in a new window instead)
  155.  *  "tabshifted"  same as "tab" but in background if default is to select new tabs, and vice versa
  156.  *  "window"      new window
  157.  *  "save"        save to disk (with no filename hint!)
  158.  *
  159.  * allowThirdPartyFixup controls whether third party services such as Google's
  160.  * I Feel Lucky are allowed to interpret this URL. This parameter may be
  161.  * undefined, which is treated as false.
  162.  */
  163. function openUILinkIn( url, where, allowThirdPartyFixup, postData, referrerUrl )
  164. {
  165.   if (!where || !url)
  166.     return;
  167.  
  168.   if (where == "save") {
  169.     saveURL(url, null, null, true, null, referrerUrl);
  170.     return;
  171.   }
  172.   const Cc = Components.classes;
  173.   const Ci = Components.interfaces;
  174.  
  175.   var w = getTopWin();
  176.  
  177.   if (!w || where == "window") {
  178.     var sa = Cc["@mozilla.org/supports-array;1"].
  179.              createInstance(Ci.nsISupportsArray);
  180.  
  181.     var wuri = Cc["@mozilla.org/supports-string;1"].
  182.                createInstance(Ci.nsISupportsString);
  183.     wuri.data = url;
  184.  
  185.     sa.AppendElement(wuri);
  186.     sa.AppendElement(null);
  187.     sa.AppendElement(referrerUrl);
  188.     sa.AppendElement(postData);
  189.     sa.AppendElement(allowThirdPartyFixup);
  190.  
  191.     var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
  192.              getService(Ci.nsIWindowWatcher);
  193.  
  194.     ww.openWindow(w || window,
  195.                   getBrowserURL(),
  196.                   null,
  197.                   "chrome,dialog=no,all",
  198.                   sa);
  199.  
  200.     return;
  201.   }
  202.  
  203.   var loadInBackground = getBoolPref("browser.tabs.loadBookmarksInBackground", false);
  204.  
  205.   switch (where) {
  206.   case "current":
  207.     w.loadURI(url, referrerUrl, postData, allowThirdPartyFixup);
  208.     break;
  209.   case "tabshifted":
  210.     loadInBackground = !loadInBackground;
  211.     // fall through
  212.   case "tab":
  213.     var browser = w.getBrowser();
  214.     browser.loadOneTab(url, referrerUrl, null, postData, loadInBackground,
  215.                        allowThirdPartyFixup || false);
  216.     break;
  217.   }
  218.  
  219.   // Call focusElement(w.content) instead of w.content.focus() to make sure
  220.   // that we don't raise the old window, since the URI we just loaded may have
  221.   // resulted in a new frontmost window (e.g. "javascript:window.open('');").
  222.   focusElement(w.content);
  223. }
  224.  
  225. // Used as an onclick handler for UI elements with link-like behavior.
  226. // e.g. onclick="checkForMiddleClick(this, event);"
  227. function checkForMiddleClick(node, event) {
  228.   // We should be using the disabled property here instead of the attribute,
  229.   // but some elements that this function is used with don't support it (e.g.
  230.   // menuitem).
  231.   if (node.getAttribute("disabled") == "true")
  232.     return; // Do nothing
  233.  
  234.   if (event.button == 1) {
  235.     /* Execute the node's oncommand or command.
  236.      *
  237.      * XXX: we should use node.oncommand(event) once bug 246720 is fixed.
  238.      */
  239.     var target = node.hasAttribute("oncommand") ? node :
  240.                  node.ownerDocument.getElementById(node.getAttribute("command"));
  241.     var fn = new Function("event", target.getAttribute("oncommand"));
  242.     fn.call(target, event);
  243.  
  244.     // If the middle-click was on part of a menu, close the menu.
  245.     // (Menus close automatically with left-click but not with middle-click.)
  246.     closeMenus(event.target);
  247.   }
  248. }
  249.  
  250. // Closes all popups that are ancestors of the node.
  251. function closeMenus(node)
  252. {
  253.   if ("tagName" in node) {
  254.     if (node.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
  255.     && (node.tagName == "menupopup" || node.tagName == "popup"))
  256.       node.hidePopup();
  257.  
  258.     closeMenus(node.parentNode);
  259.   }
  260. }
  261.  
  262. // Gather all descendent text under given document node.
  263. function gatherTextUnder ( root ) 
  264. {
  265.   var text = "";
  266.   var node = root.firstChild;
  267.   var depth = 1;
  268.   while ( node && depth > 0 ) {
  269.     // See if this node is text.
  270.     if ( node.nodeType == Node.TEXT_NODE ) {
  271.       // Add this text to our collection.
  272.       text += " " + node.data;
  273.     } else if ( node instanceof HTMLImageElement) {
  274.       // If it has an alt= attribute, use that.
  275.       var altText = node.getAttribute( "alt" );
  276.       if ( altText && altText != "" ) {
  277.         text = altText;
  278.         break;
  279.       }
  280.     }
  281.     // Find next node to test.
  282.     // First, see if this node has children.
  283.     if ( node.hasChildNodes() ) {
  284.       // Go to first child.
  285.       node = node.firstChild;
  286.       depth++;
  287.     } else {
  288.       // No children, try next sibling.
  289.       if ( node.nextSibling ) {
  290.         node = node.nextSibling;
  291.       } else {
  292.         // Last resort is our next oldest uncle/aunt.
  293.         node = node.parentNode.nextSibling;
  294.         depth--;
  295.       }
  296.     }
  297.   }
  298.   // Strip leading whitespace.
  299.   text = text.replace( /^\s+/, "" );
  300.   // Strip trailing whitespace.
  301.   text = text.replace( /\s+$/, "" );
  302.   // Compress remaining whitespace.
  303.   text = text.replace( /\s+/g, " " );
  304.   return text;
  305. }
  306.  
  307. function getShellService()
  308. {
  309.   var shell = null;
  310.   try {
  311.     shell = Components.classes["@mozilla.org/browser/shell-service;1"]
  312.       .getService(Components.interfaces.nsIShellService);
  313.   } catch (e) {dump("*** e = " + e + "\n");}
  314.   return shell;
  315. }
  316.  
  317. function isBidiEnabled() {
  318.   // first check the pref.
  319.   if (getBoolPref("bidi.browser.ui", false))
  320.     return true;
  321.  
  322.   // if the pref isn't set, check for an RTL locale and force the pref to true
  323.   // if we find one.
  324.   var rv = false;
  325.  
  326.   try {
  327.     var localeService = Components.classes["@mozilla.org/intl/nslocaleservice;1"]
  328.                                   .getService(Components.interfaces.nsILocaleService);
  329.     var systemLocale = localeService.getSystemLocale().getCategory("NSILOCALE_CTYPE").substr(0,3);
  330.  
  331.     switch (systemLocale) {
  332.       case "ar-":
  333.       case "he-":
  334.       case "fa-":
  335.       case "ur-":
  336.       case "syr":
  337.         rv = true;
  338.         var pref = Components.classes["@mozilla.org/preferences-service;1"]
  339.                              .getService(Components.interfaces.nsIPrefBranch);
  340.         pref.setBoolPref("bidi.browser.ui", true);
  341.     }
  342.   } catch (e) {}
  343.  
  344.   return rv;
  345. }
  346.  
  347. function openAboutDialog()
  348. {
  349. //@line 401 "e:\builds\moz2_slave\win32_build\build\browser\base\content\utilityOverlay.js"
  350.   window.openDialog("chrome://browser/content/aboutDialog.xul", "About", "centerscreen,chrome,resizable=no");
  351. //@line 403 "e:\builds\moz2_slave\win32_build\build\browser\base\content\utilityOverlay.js"
  352. }
  353.  
  354. function openPreferences(paneID, extraArgs)
  355. {
  356.   var instantApply = getBoolPref("browser.preferences.instantApply", false);
  357.   var features = "chrome,titlebar,toolbar,centerscreen" + (instantApply ? ",dialog=no" : ",modal");
  358.  
  359.   var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  360.                      .getService(Components.interfaces.nsIWindowMediator);
  361.   var win = wm.getMostRecentWindow("Browser:Preferences");
  362.   if (win) {
  363.     win.focus();
  364.     if (paneID) {
  365.       var pane = win.document.getElementById(paneID);
  366.       win.document.documentElement.showPane(pane);
  367.     }
  368.  
  369.     if (extraArgs && extraArgs["advancedTab"]) {
  370.       var advancedPaneTabs = win.document.getElementById("advancedPrefs");
  371.       advancedPaneTabs.selectedTab = win.document.getElementById(extraArgs["advancedTab"]);
  372.     }
  373.  
  374.     return win;
  375.   }
  376.  
  377.   return openDialog("chrome://browser/content/preferences/preferences.xul",
  378.                     "Preferences", features, paneID, extraArgs);
  379. }
  380.  
  381. function openAdvancedPreferences(tabID)
  382. {
  383.   return openPreferences("paneAdvanced", { "advancedTab" : tabID });
  384. }
  385.  
  386. /**
  387.  * Opens the release notes page for this version of the application.
  388.  */
  389. function openReleaseNotes()
  390. {
  391.   var formatter = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
  392.                             .getService(Components.interfaces.nsIURLFormatter);
  393.   var relnotesURL = formatter.formatURLPref("app.releaseNotesURL");
  394.   
  395.   openUILinkIn(relnotesURL, "tab");
  396. }
  397.  
  398. //@line 450 "e:\builds\moz2_slave\win32_build\build\browser\base\content\utilityOverlay.js"
  399. /**
  400.  * Opens the update manager and checks for updates to the application.
  401.  */
  402. function checkForUpdates()
  403. {
  404.   var um = 
  405.       Components.classes["@mozilla.org/updates/update-manager;1"].
  406.       getService(Components.interfaces.nsIUpdateManager);
  407.   var prompter = 
  408.       Components.classes["@mozilla.org/updates/update-prompt;1"].
  409.       createInstance(Components.interfaces.nsIUpdatePrompt);
  410.  
  411.   // If there's an update ready to be applied, show the "Update Downloaded"
  412.   // UI instead and let the user know they have to restart the browser for
  413.   // the changes to be applied. 
  414.   if (um.activeUpdate && um.activeUpdate.state == "pending")
  415.     prompter.showUpdateDownloaded(um.activeUpdate);
  416.   else
  417.     prompter.checkForUpdates();
  418. }
  419. //@line 471 "e:\builds\moz2_slave\win32_build\build\browser\base\content\utilityOverlay.js"
  420.  
  421. function buildHelpMenu()
  422. {
  423.   // Enable/disable the "Report Web Forgery" menu item.  safebrowsing object
  424.   // may not exist in OSX
  425.   if (typeof safebrowsing != "undefined")
  426.     safebrowsing.setReportPhishingMenu();
  427.  
  428. //@line 480 "e:\builds\moz2_slave\win32_build\build\browser\base\content\utilityOverlay.js"
  429.   var updates = 
  430.       Components.classes["@mozilla.org/updates/update-service;1"].
  431.       getService(Components.interfaces.nsIApplicationUpdateService);
  432.   var um = 
  433.       Components.classes["@mozilla.org/updates/update-manager;1"].
  434.       getService(Components.interfaces.nsIUpdateManager);
  435.  
  436.   // Disable the UI if the update enabled pref has been locked by the 
  437.   // administrator or if we cannot update for some other reason
  438.   var checkForUpdates = document.getElementById("checkForUpdates");
  439.   var canUpdate = updates.canUpdate;
  440.   checkForUpdates.setAttribute("disabled", !canUpdate);
  441.   if (!canUpdate)
  442.     return; 
  443.  
  444.   var strings = document.getElementById("bundle_browser");
  445.   var activeUpdate = um.activeUpdate;
  446.   
  447.   // If there's an active update, substitute its name into the label
  448.   // we show for this item, otherwise display a generic label.
  449.   function getStringWithUpdateName(key) {
  450.     if (activeUpdate && activeUpdate.name)
  451.       return strings.getFormattedString(key, [activeUpdate.name]);
  452.     return strings.getString(key + "Fallback");
  453.   }
  454.   
  455.   // By default, show "Check for Updates..."
  456.   var key = "default";
  457.   if (activeUpdate) {
  458.     switch (activeUpdate.state) {
  459.     case "downloading":
  460.       // If we're downloading an update at present, show the text:
  461.       // "Downloading Firefox x.x..." otherwise we're paused, and show
  462.       // "Resume Downloading Firefox x.x..."
  463.       key = updates.isDownloading ? "downloading" : "resume";
  464.       break;
  465.     case "pending":
  466.       // If we're waiting for the user to restart, show: "Apply Downloaded
  467.       // Updates Now..."
  468.       key = "pending";
  469.       break;
  470.     }
  471.   }
  472.   checkForUpdates.label = getStringWithUpdateName("updatesItem_" + key);
  473.   if (um.activeUpdate && updates.isDownloading)
  474.     checkForUpdates.setAttribute("loading", "true");
  475.   else
  476.     checkForUpdates.removeAttribute("loading");
  477. //@line 532 "e:\builds\moz2_slave\win32_build\build\browser\base\content\utilityOverlay.js"
  478. }
  479.  
  480. function isElementVisible(aElement)
  481. {
  482.   if (!aElement)
  483.     return false;
  484.  
  485.   // If aElement or a direct or indirect parent is hidden or collapsed,
  486.   // height, width or both will be 0.
  487.   var bo = aElement.boxObject;
  488.   return (bo.height > 0 && bo.width > 0);
  489. }
  490.  
  491. function makeURLAbsolute(aBase, aUrl)
  492. {
  493.   // Note:  makeURI() will throw if aUri is not a valid URI
  494.   return makeURI(aUrl, null, makeURI(aBase)).spec;
  495. }
  496.  
  497. function getBrowserFromContentWindow(aContentWindow)
  498. {
  499.   var browsers = gBrowser.browsers;
  500.   for (var i = 0; i < browsers.length; i++) {
  501.     if (browsers[i].contentWindow == aContentWindow)
  502.       return browsers[i];
  503.   }
  504.   return null;
  505. }
  506.  
  507.  
  508. /**
  509.  * openNewTabWith: opens a new tab with the given URL.
  510.  *
  511.  * @param aURL
  512.  *        The URL to open (as a string).
  513.  * @param aDocument
  514.  *        The document from which the URL came, or null. This is used to set the
  515.  *        referrer header and to do a security check of whether the document is
  516.  *        allowed to reference the URL. If null, there will be no referrer
  517.  *        header and no security check.
  518.  * @param aPostData
  519.  *        Form POST data, or null.
  520.  * @param aEvent
  521.  *        The triggering event (for the purpose of determining whether to open
  522.  *        in the background), or null.
  523.  * @param aAllowThirdPartyFixup
  524.  *        If true, then we allow the URL text to be sent to third party services
  525.  *        (e.g., Google's I Feel Lucky) for interpretation. This parameter may
  526.  *        be undefined in which case it is treated as false.
  527.  * @param [optional] aReferrer
  528.  *        If aDocument is null, then this will be used as the referrer.
  529.  *        There will be no security check.
  530.  */ 
  531. function openNewTabWith(aURL, aDocument, aPostData, aEvent,
  532.                         aAllowThirdPartyFixup, aReferrer)
  533. {
  534.   if (aDocument)
  535.     urlSecurityCheck(aURL, aDocument.nodePrincipal);
  536.  
  537.   var prefSvc = Components.classes["@mozilla.org/preferences-service;1"]
  538.                           .getService(Components.interfaces.nsIPrefService);
  539.   prefSvc = prefSvc.getBranch(null);
  540.  
  541.   // should we open it in a new tab?
  542.   var loadInBackground = true;
  543.   try {
  544.     loadInBackground = prefSvc.getBoolPref("browser.tabs.loadInBackground");
  545.   }
  546.   catch(ex) {
  547.   }
  548.  
  549.   if (aEvent && aEvent.shiftKey)
  550.     loadInBackground = !loadInBackground;
  551.  
  552.   // As in openNewWindowWith(), we want to pass the charset of the
  553.   // current document over to a new tab. 
  554.   var wintype = document.documentElement.getAttribute("windowtype");
  555.   var originCharset;
  556.   if (wintype == "navigator:browser")
  557.     originCharset = window.content.document.characterSet;
  558.  
  559.   // open link in new tab
  560.   var referrerURI = aDocument ? aDocument.documentURIObject : aReferrer;
  561.   var browser = top.document.getElementById("content");
  562.   return browser.loadOneTab(aURL, referrerURI, originCharset, aPostData,
  563.                             loadInBackground, aAllowThirdPartyFixup || false);
  564. }
  565.  
  566. function openNewWindowWith(aURL, aDocument, aPostData, aAllowThirdPartyFixup,
  567.                            aReferrer)
  568. {
  569.   if (aDocument)
  570.     urlSecurityCheck(aURL, aDocument.nodePrincipal);
  571.  
  572.   // if and only if the current window is a browser window and it has a
  573.   // document with a character set, then extract the current charset menu
  574.   // setting from the current document and use it to initialize the new browser
  575.   // window...
  576.   var charsetArg = null;
  577.   var wintype = document.documentElement.getAttribute("windowtype");
  578.   if (wintype == "navigator:browser")
  579.     charsetArg = "charset=" + window.content.document.characterSet;
  580.  
  581.   var referrerURI = aDocument ? aDocument.documentURIObject : aReferrer;
  582.   return window.openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no",
  583.                            aURL, charsetArg, referrerURI, aPostData,
  584.                            aAllowThirdPartyFixup);
  585. }
  586.  
  587. /**
  588.  * isValidFeed: checks whether the given data represents a valid feed.
  589.  *
  590.  * @param  aLink
  591.  *         An object representing a feed with title, href and type.
  592.  * @param  aPrincipal
  593.  *         The principal of the document, used for security check.
  594.  * @param  aIsFeed
  595.  *         Whether this is already a known feed or not, if true only a security
  596.  *         check will be performed.
  597.  */ 
  598. function isValidFeed(aLink, aPrincipal, aIsFeed)
  599. {
  600.   if (!aLink || !aPrincipal)
  601.     return false;
  602.  
  603.   var type = aLink.type.toLowerCase().replace(/^\s+|\s*(?:;.*)?$/g, "");
  604.   if (!aIsFeed) {
  605.     aIsFeed = (type == "application/rss+xml" ||
  606.                type == "application/atom+xml");
  607.   }
  608.  
  609.   if (aIsFeed) {
  610.     try {
  611.       urlSecurityCheck(aLink.href, aPrincipal,
  612.                        Components.interfaces.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
  613.       return type || "application/rss+xml";
  614.     }
  615.     catch(ex) {
  616.     }
  617.   }
  618.  
  619.   return null;
  620. }
  621.  
  622. // aCalledFromModal is optional
  623. function openHelpLink(aHelpTopic, aCalledFromModal) {
  624.   var url = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
  625.                       .getService(Components.interfaces.nsIURLFormatter)
  626.                       .formatURLPref("app.support.baseURL");
  627.   url += aHelpTopic;
  628.  
  629.   var where = aCalledFromModal ? "window" : "tab";
  630.   openUILinkIn(url, where);
  631. }
  632.  
  633. function openPrefsHelp() {
  634.   var prefs = Components.classes["@mozilla.org/preferences-service;1"]
  635.                         .getService(Components.interfaces.nsIPrefBranch2);
  636.  
  637.   // non-instant apply prefwindows are usually modal, so we can't open in the topmost window, 
  638.   // since its probably behind the window.
  639.   var instantApply = prefs.getBoolPref("browser.preferences.instantApply");
  640.  
  641.   var helpTopic = document.getElementsByTagName("prefwindow")[0].currentPane.helpTopic;
  642.   openHelpLink(helpTopic, !instantApply);
  643. }
  644.